package com.meeting.meetingroom_api.specification;

import com.meeting.meetingroom_api.entity.Booking;
import com.meeting.meetingroom_api.dto.BookingQueryDto;
import jakarta.persistence.criteria.*;
import org.springframework.data.jpa.domain.Specification;

import java.util.ArrayList;
import java.util.List;
//支持按最接近当前时间排序查询
public class BookingSpecification {

    public static Specification<Booking> findByCriteria(BookingQueryDto queryDto) {
        return (Root<Booking> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (queryDto.getCustomerId() != null) {
                predicates.add(cb.equal(root.get("customer").get("userId"), queryDto.getCustomerId()));
            }
            if (queryDto.getRoomId() != null) {
                predicates.add(cb.equal(root.get("room").get("roomId"), queryDto.getRoomId()));
            }
            if (queryDto.getStatus() != null) {
                predicates.add(cb.equal(root.get("status"), queryDto.getStatus()));
            }
            if (queryDto.getStatusList() != null && !queryDto.getStatusList().isEmpty()) {
                // 使用in查询代替单个equal
                predicates.add(root.get("status").in(queryDto.getStatusList()));
            }
            
            // 时间范围查询：查找在指定时间范围内的预订
            if (queryDto.getStartDatetime() != null && queryDto.getEndDatetime() != null) {
                // 查找与指定时间段有重叠的预订
                Predicate timeOverlap = cb.or(
                    // 预订的开始时间在查询时间段内
                    cb.and(
                        cb.greaterThanOrEqualTo(root.get("startDatetime"), queryDto.getStartDatetime()),
                        cb.lessThan(root.get("startDatetime"), queryDto.getEndDatetime())
                    ),
                    // 预订的结束时间在查询时间段内
                    cb.and(
                        cb.greaterThan(root.get("endDatetime"), queryDto.getStartDatetime()),
                        cb.lessThanOrEqualTo(root.get("endDatetime"), queryDto.getEndDatetime())
                    ),
                    // 预订完全包含查询时间段
                    cb.and(
                        cb.lessThanOrEqualTo(root.get("startDatetime"), queryDto.getStartDatetime()),
                        cb.greaterThanOrEqualTo(root.get("endDatetime"), queryDto.getEndDatetime())
                    )
                );
                predicates.add(timeOverlap);
            }
            
            // 单独的开始时间过滤
            if (queryDto.getStartDatetime() != null && queryDto.getEndDatetime() == null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("startDatetime"), queryDto.getStartDatetime()));
            }
            
            // 单独的结束时间过滤  
            if (queryDto.getEndDatetime() != null && queryDto.getStartDatetime() == null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("endDatetime"), queryDto.getEndDatetime()));
            }
            //计算距离当前最近时间，进行排序
            // 获取当前时间的毫秒数
            Expression<Long> currentTimeMillis = cb.literal(System.currentTimeMillis());

            // 将 LocalDateTime 转换为毫秒数
            Expression<Long> startDateTimeMillis = cb.function(
                    "UNIX_TIMESTAMP",  // 转换为秒
                    Long.class,
                    root.get("startDatetime")
            );

            // 转换为毫秒（乘以 1000）
            Expression<Long> startDateTimeMillisExpanded = cb.prod(startDateTimeMillis, 1000L);

            // 计算绝对时间差（毫秒）
            Expression<Long> timeDiffMillis = cb.abs(
                    cb.diff(startDateTimeMillisExpanded, currentTimeMillis)
            );

            // 设置排序（按时间差升序）
            assert query != null;
            query.orderBy(cb.asc(timeDiffMillis));

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }
}